<?php

require_once(BaseConfig::LoadClass('conecta.class.php'       ));
require_once(BaseConfig::LoadClass('operaciones_db.class.php'));

/**
 * Clase base para los objetos que pueden ser editados, añadidos, etc
 */
class ObjetoBase {
  /**
   * Tabla a la que se hace referencia
   *
   * @var String
   * @example 'usuarios'
   */
  var $__strTablaReferencia;

  /**
   * Cadena que dice cual es el indice de este objeto
   *
   * @var String
   * @example 'id_usuario'
   */
  var $__strNombreIndice;

  /**
   * Arreglo que contiene los nombres de los campos y los nombres de las variables
   *
   * @var Array 
   * @example $this->__arrMapaDatos['id_usuario'] = 'intIdUsuario'
   */
  var $__arrMapaDatos;

  /**
   * Arreglo que contiene los nombres de los campos
   *
   * @var Array 
   * @example $this->__arrMapaNombres['id_usuario'] = 'id_usuario'
   */
  var $__arrMapaNombres;

  /**
   * Arreglo que contiene los tipos de los campos
   *
   * @var Array
   * @example $this->__arrMapaTipos['id_usuario'] = 'I'
   */
  var $__arrMapaTipos;

  /**
   * Función que actua como constructor interno para el objeto cuando es heredado
   *
   * @param String $strTabla        Tabla a la que se hace referencia
   * @param Array  $arrMapaDatos    Mapa de los datos que se afectaran, del tipo $arrMapaDatos[NombreColumna] = Array('NombreVariable', 'TipoVariable');
   * @param Array  $strNombreIndice Indice de la tabla
   */
  function __ArmarDatosPrivados($strTabla, $arrMapaDatos, $strNombreIndice) {
    $this->__strTablaReferencia = $strTabla       ;
    $this->__strNombreIndice    = $strNombreIndice;

    $this->__arrMapaDatos   = Array();
    $this->__arrMapaTipos   = Array();
    $this->__arrMapaNombres = Array();

    foreach($arrMapaDatos as $strNombreColumna => $arrDatosColumna) {
      $this->__arrMapaNombres[$strNombreColumna] = $strNombreColumna;
      $this->__arrMapaDatos  [$strNombreColumna] = $arrDatosColumna['NombreVariable'];
      $this->__arrMapaTipos  [$strNombreColumna] = $arrDatosColumna['TipoVariable'  ];
    }

    // Poner al indice como de tipo I
    $this->__arrMapaTipos[$strNombreIndice] = 'I';
  }

  /**
   * Función que obtiene el query para guardar el objeto actual
   *
   * @param boolean $bolHacerLlamada    Si también se ejecutará la consulta
   * @param boolean $bolObtenerIdCreado Si se necesita obtener el ID creado cuando se hace un INSERT
   * @param boolean $bolGenerarIndice   Si se necesita generar el ID de un indice porque no es autonumerico al crear
   * 
   * @return String Cadena de query a ejecutar
   */
  function GuardarObjeto($bolHacerLlamada = true, $bolObtenerIdCreado = false, $bolGenerarIndice = false) {
    $oConecta        = new Conecta();
    $strConsulta     = '';
    $arrDatosValores = Array();
    
    foreach($this->__arrMapaDatos as $strNombreColumna => $strNombreVariable) {
      $arrDatosValores[$strNombreColumna] = $this->$strNombreVariable;
    }

    if(($this->__strNombreIndice) && (($arrDatosValores[$this->__strNombreIndice]) - 0)) {
      $strConsulta = OperacionesDB::CrearUpdate($this->__strTablaReferencia, $this->__arrMapaNombres, $this->__arrMapaTipos, $arrDatosValores);
    } else {
      if($bolGenerarIndice) {
        $strConsulta = "SELECT MAX({$this->__strNombreIndice}) AS maximo FROM {$this->__strTablaReferencia}";
        $oConecta->Consulta($strConsulta);
        $arrDatosValores[$this->__strNombreIndice] = ($oConecta->Field('maximo') + 1);
        eval('$this->' . $this->__arrMapaDatos[$this->__strNombreIndice] . ' = "' . ($oConecta->Field('maximo') + 1) . '";');
        $this->__arrMapaTipos[$this->__strNombreIndice] = "S";
        $strConsulta = OperacionesDB::CrearInsert($this->__strTablaReferencia, $this->__arrMapaNombres, $this->__arrMapaTipos, $arrDatosValores);
        $this->__arrMapaTipos[$this->__strNombreIndice] = "I";
      } else {
        $strConsulta = OperacionesDB::CrearInsert($this->__strTablaReferencia, $this->__arrMapaNombres, $this->__arrMapaTipos, $arrDatosValores);
      }
    }

    if($bolHacerLlamada) {
      $oConecta->Consulta($strConsulta);
      
      if($bolObtenerIdCreado) {
        if(($this->__strNombreIndice) && (!(($arrDatosValores[$this->__strNombreIndice]) - 0))) {
          $strNombreIndice = $this->__arrMapaDatos[$this->__strNombreIndice];
          $this->$strNombreIndice = $oConecta->GetInsertedID();
        }
      }
    }
    
    return $strConsulta;
  }
  
  /**
   * Función que borra un elemento de la base de datos.
   * Para que el borrado se haga, se necesita pasar el parametro 
   * $bolHacerLlamada = true, de lo contrario solo se regresará la consulta
   * necesaria para borrar el elemento.
   * 
   * Si el indice del objeto actual es 0, no se borrará ningun elemento.
   * 
   * @param boolean $bolHacerLlamada Si se borrará efectivamente la columna
   */
  function BorrarObjeto($bolHacerLlamada = false) {
    if($this->{$this->__arrMapaDatos[$this->__strNombreIndice]} != 0) {
      $strConsulta = "DELETE FROM {$this->__strTablaReferencia} WHERE {$this->__strNombreIndice} = {$this->{$this->__arrMapaDatos[$this->__strNombreIndice]}}";
    } else {
      $strConsulta = "";
    }
    
    if($bolHacerLlamada) {
      $oConecta = new Conecta();
      $oConecta->Consulta($strConsulta);
    }
    
    return $strConsulta;
  }

  function GuardarObjetoConIndiceCadena($bolHacerLlamada = true) {
    $strConsulta = '';
    $oConecta    = new Conecta();

    $arrDatosValores = Array();
    foreach($this->__arrMapaDatos as $strNombreColumna => $strNombreVariable) {
      $arrDatosValores[$strNombreColumna] = $this->$strNombreVariable;
    }

    // Ver si existe el indice en las tablas
    $strConsulta = "SELECT {$this->__strNombreIndice} FROM {$this->__strTablaReferencia} WHERE {$this->__strNombreIndice} = '{$arrDatosValores[$this->__strNombreIndice]}'";
    $oConecta->Consulta($strConsulta);
    if(!$oConecta->EOF) {
      $this->__arrMapaTipos[$this->__strNombreIndice] = "IS";
      $strConsulta = OperacionesDB::CrearUpdate($this->__strTablaReferencia, $this->__arrMapaNombres, $this->__arrMapaTipos, $arrDatosValores);
      $this->__arrMapaTipos[$this->__strNombreIndice] = "I";
    } else {
      $this->__arrMapaTipos[$this->__strNombreIndice] = "S";
      $strConsulta = OperacionesDB::CrearInsert($this->__strTablaReferencia, $this->__arrMapaNombres, $this->__arrMapaTipos, $arrDatosValores);
      $this->__arrMapaTipos[$this->__strNombreIndice] = "I";
    }

    if($bolHacerLlamada) {
      $oConecta->Consulta($strConsulta);
    }

    return $strConsulta;
  }
  
  /**
   * Función que limpia el objeto actual
   */
  function LimpiarObjeto() {
    foreach($this->__arrMapaDatos as $strNombreColumna => $strNombreVariable) {
      switch($this->__arrMapaTipos[$strNombreColumna]) {
        case 'I': case 'N':
          $this->$strNombreVariable = 0;
          break;
        case 'D':
          $this->$strNombreVariable = '0000-01-01 00:00:00';
          break;
        case 'S': default:
          $this->$strNombreVariable = '';
          break;
      }
    }
  }

  /**
   * Función que llena al objeto actual con los elementos de un query
   *
   * @param Array $arrDatos Datos con los que se llenará el objeto. Generalmente es el resultado de Conecta::GetColumn
   */
  function LlenarObjeto($arrDatos) {
    foreach($this->__arrMapaDatos as $strNombreColumna => $strNombreVariable) {
      if(isset($arrDatos[$strNombreColumna])) {
        $this->$strNombreVariable = $arrDatos[$strNombreColumna];
      }
    }
  }

  /**
   * Obtiene un arreglo con los datos del objeto en un formato accesible para guardarlos
   *
   * @return Array
   */
  function ObtenerArregloDatos() {
    $arrDatos = array();
    foreach($this->__arrMapaDatos as $strNombreColumna => $strNombreVariable) {
      $arrDatos[$strNombreColumna] = $this->$strNombreVariable;
    }
    return $arrDatos;
  }

  /**
   * Función que llena al objeto haciendo una búsqueda por ID
   *
   * @param int $intId el ID que se buscará
   */
  function SeleccionarPorIndice($intId) {
    $oConecta = new Conecta();
    if(!($intId - 0)) {
      $this->LimpiarObjeto();
      return;
    }

    $strConsulta = 'SELECT * FROM ' . $this->__strTablaReferencia . ' WHERE ' . $this->__strNombreIndice . ' = ' . ($intId - 0);
    $oConecta->Consulta($strConsulta);
    
    if($oConecta->EOF) {
      $this->LimpiarObjeto();
    } else {
      $this->LlenarObjeto($oConecta->GetColumn());
    }
  }

  /**
   * Función que llena al objeto haciendo una búsqueda por ID no numerico
   *
   * @param String $strId el ID que se buscará
   */
  function SeleccionarPorIndiceNoNumerico($strId) {
    $oConecta = new Conecta();

    $strConsulta = 'SELECT * FROM ' . $this->__strTablaReferencia . ' WHERE ' . $this->__strNombreIndice . ' = \'' . ($strId) . '\'';
    $oConecta->Consulta($strConsulta);

    if($oConecta->EOF) {
      $this->LimpiarObjeto();
    } else {
      $this->LlenarObjeto($oConecta->GetColumn());
    }
  }

  /**
   * Función que crea varios objetos de tipo $StrClassName (Los objetos cuyos
   * indices se encuentran en $arrIndices).
   *
   * @param Array  $arrIndices   Arreglo con los indices a cargar
   * @param String $strClassName Nombre de la clase (P.Ej. 'HoldBack')
   * 
   * @return Array Arreglo con los objetos fabricados
   */
  static function Fabrica($arrIndices, $strClassName) {
    $arrRet = array();
    
    foreach($arrIndices as $intIndice) {
      eval("\$arrRet[] = new $strClassName($intIndice);");
    }
    
    return $arrRet;
  }
  
  /**
   * Función que crea varios objetos de tipo $StrClassName obtenidos desde la
   * consulta $strConsulta
   *
   * @param String  $strConsulta    Consulta que se ejecutará (SELECT * FROM) de donde se obtienen los datos
   * @param String  $strClassName   Nombre de la clase (P.Ej. 'HoldBack')
   * @param boolean $bolSoloIndices Si se pone como verdafero, la consulta solo obtiene los ID y con ellos se obtienen los objetos. Si es false, la consulta ya trae los datos completos
   * @return array  Arreglo con los objetos fabricados
   */
  static function FabricaCon($strConsulta, $strClassName, $bolSoloIndices = false) {
    $oConecta = new Conecta();
    $oConecta->Consulta($strConsulta);
    if($bolSoloIndices) {
      return ObjetoBase::Fabrica($oConecta->GetCompleteRes(), $strClassName);
    } else {
      $arrRet = array();
      $i = 0;
      while(!$oConecta->EOF) {
        eval("\$arrRet[$i] = new $strClassName();");
        $arrRet[$i]->LlenarObjeto($oConecta->GetColumn());
        $i++;
        $oConecta->MoveNext();
      }

      return $arrRet;
    }
  }
  
  function __CrearConsultaCreacion() {
    $strConsulta = "";
    $strConsulta = "CREATE TABLE {$this->__strTablaReferencia} (";
    foreach($this->__arrMapaNombres as $strNombreIndice) {
      $strConsulta .= "\n  $strNombreIndice ";
      switch($this->__arrMapaTipos[$strNombreIndice]) {
        case 'I':
          $strConsulta .= "INT NOT NULL AUTO_INCREMENT PRIMARY KEY, ";
          break;
        case 'N':
          // Checar si es un float segun el nombre de la variable
          if(substr($this->__arrMapaDatos[$strNombreIndice], 0, 3) == "flt") {
            $strConsulta .= "DECIMAL(22,6), ";
          } else {
            $strConsulta .= "INT, ";
          }
          break;
        case 'D':
          $strConsulta .= "DATETIME, ";
          break;
        case 'S':
          $strConsulta .= "VARCHAR(250), ";
          break;
      }
    }
    $strConsulta = substr($strConsulta, 0, -2) . "\n)";
    return $strConsulta;
  }
}

?>
